
namespace Derm.Render.Shaders.Standard {

	/// <summary>
	/// Predefined shader program.
	/// </summary>
	public class StandardShader : ShaderProgram
	{
		#region Constructors

		/// <summary>
		/// Construct a StandardShader.
		/// </summary>
		public StandardShader() : base("StandardShader")
		{
			// Attach all required vertex shaders
			AttachShader(VertexShader.LibraryId, ShaderObject.Stage.Vertex);
			// Lazy attach for shader ProjectRigidVertex (Vertex): implements ProjectVertex interface

			// Attach all required fragment shaders
			AttachShader(FragmentShader.LibraryId, ShaderObject.Stage.Fragment);

			// This program defines its own attribute semantics
			SetAttributeSemantic("ds_VertexPosition", "Position");
			SetAttributeSemantic("ds_VertexColor", "Color");
			SetAttributeSemantic("ds_VertexNormal", "Normal");
			SetAttributeSemantic("ds_VertexTexCoord", "TexCoord");
		}

		/// <summary>
		/// A string that identifies this ShaderProgram implementation in ShaderLibraryConfiguration.
		/// </summary>
		public static readonly string LibraryId = "StandardShader";

		#endregion

		#region ShaderProgram Overrides

		/// <summary>
		/// Construct a StandardShader.
		/// </summary>
		protected override void LinkInterfaces()
		{
			// Implements all required vertex shaders interfaces
			if (HasInterface("ProjectVertex") == false)
				AttachShader(ProjectRigidVertex.LibraryId, ShaderObject.Stage.Vertex);
		}

		#endregion

	}

	/// <summary>
	/// Shader source generated from VertexShader shader source file.
	/// </summary>
	public class VertexShader : ShaderObject
	{
		#region Constructors

		/// <summary>
		/// Construct a VertexShader defining itself a vertex shader.
		/// </summary>
		public VertexShader() : base(Stage.Vertex, "Derm/Shaders/Standard/VertexShader") { }

		/// <summary>
		/// A string that identifies this ShaderObject implementation in ShaderLibraryConfiguration.
		/// </summary>
		public static readonly string LibraryId = "Derm.Shaders.Standard.VertexShader";

		#endregion

		#region ShaderObject Overrides

		/// <summary>
		/// The only stage that this ShaderObject can link.
		/// </summary>
		public static readonly Stage LibraryStage = Stage.Vertex;

		/// <summary>
		/// The source string read from Derm/Shaders/Standard/VertexShader.
		/// </summary>
		protected override string[] Source { get { return (sShaderSource); } }

		/// <summary>
		/// The source string read from Derm/Shaders/Standard/VertexShader.
		/// </summary>
		private static readonly string[] sShaderSource = new string[] {
			"",
			"//  Copyright (C) 2011-2012 Luca Piccioni",
			"// ",
			"//  This program is free software: you can redistribute it and/or modify",
			"//  it under the terms of the GNU General Public License as published by",
			"//  the Free Software Foundation, either version 3 of the License, or",
			"//  (at your option) any later version.",
			"// ",
			"//  This program is distributed in the hope that it will be useful,",
			"//  but WITHOUT ANY WARRANTY; without even the implied warranty of",
			"//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the",
			"//  GNU General Public License for more details.",
			"// ",
			"//  You should have received a copy of the GNU General Public License",
			"//  along with this program.  If not, see <http://www.gnu.org/licenses/>.",
			"",
			"#include </Derm/Shaders/IProjectVertex>",
			"#include </Derm/Shaders/TransformState>",
			"#include </Derm/Shaders/Compatibility>",
			"",
			"#include </Derm/Shaders/Light/ILightShading>",
			"",
			"#include </Derm/Shaders/Standard/ShaderInputs>",
			"",
			"// This shader output interface",
			"BEGIN_OUTPUT_BLOCK(ShaderVaryings)",
			"	// Processed vertex color",
			"	SHADER_OUT vec4 ds_Color;",
			"	// Processed vertex position",
			"	SHADER_OUT vec4 ds_Position;",
			"	// Processed vertex normal",
			"	SHADER_OUT vec3 ds_Normal;",
			"	// Processed vertex texture coordinates",
			"	SHADER_OUT vec2 ds_TexCoord[3];",
			"END_OUTPUT_BLOCK()",
			"",
			"// Vertex shader entry point",
			"void main()",
			"{",
			"	// Compute transformed vertex position",
			"	gl_Position = ProjectVertexPosition(ds_VertexPosition);",
			"	// Vertex texture coordinate \"as is\"",
			"#if __VERSION__ >= 130",
			"	for (int i = 0; i < 3; i++)",
			"		ds_TexCoord[i] = DS_TEXTURE_ATTRIBUTE(i);",
			"#else",
			"	ds_TexCoord[0] = DS_TEXTURE_ATTRIBUTE(0);",
			"	ds_TexCoord[1] = DS_TEXTURE_ATTRIBUTE(1);",
			"	ds_TexCoord[2] = DS_TEXTURE_ATTRIBUTE(2);",
			"#endif",
			"",
			"#if defined(DS_LIGHTING_PER_VERTEX)",
			"",
			"	// Vertex color",
			"	ds_Color = ComputeLightShading(ds_FrontMaterial, ds_Model * ds_VertexPosition, ds_NormalMatrix * normalize(ds_VertexNormal));",
			"",
			"#elif defined(DS_LIGHTING_PER_FRAGMENT)",
			"",
			"	// Position is required for lighting",
			"	ds_Position = ds_Model * ds_VertexPosition;",
			"	// Normal is required for lighting",
			"	ds_Normal = ds_NormalMatrix * normalize(ds_VertexNormal);",
			"",
			"#elif defined(DS_COLOR_PER_VERTEX)",
			"",
			"	// Vertex color \"as is\"",
			"	ds_Color = ds_VertexColor;",
			"",
			"#endif",
			"}",
		};

		#endregion
	}

	/// <summary>
	/// Shader source generated from FragmentShader shader source file.
	/// </summary>
	public class FragmentShader : ShaderObject
	{
		#region Constructors

		/// <summary>
		/// Construct a FragmentShader defining itself a fragment shader.
		/// </summary>
		public FragmentShader() : base(Stage.Fragment, "Derm/Shaders/Standard/FragmentShader") { }

		/// <summary>
		/// A string that identifies this ShaderObject implementation in ShaderLibraryConfiguration.
		/// </summary>
		public static readonly string LibraryId = "Derm.Shaders.Standard.FragmentShader";

		#endregion

		#region ShaderObject Overrides

		/// <summary>
		/// The only stage that this ShaderObject can link.
		/// </summary>
		public static readonly Stage LibraryStage = Stage.Fragment;

		/// <summary>
		/// The source string read from Derm/Shaders/Standard/FragmentShader.
		/// </summary>
		protected override string[] Source { get { return (sShaderSource); } }

		/// <summary>
		/// The source string read from Derm/Shaders/Standard/FragmentShader.
		/// </summary>
		private static readonly string[] sShaderSource = new string[] {
			"",
			"//  Copyright (C) 2011-2012 Luca Piccioni",
			"// ",
			"//  This program is free software: you can redistribute it and/or modify",
			"//  it under the terms of the GNU General Public License as published by",
			"//  the Free Software Foundation, either version 3 of the License, or",
			"//  (at your option) any later version.",
			"// ",
			"//  This program is distributed in the hope that it will be useful,",
			"//  but WITHOUT ANY WARRANTY; without even the implied warranty of",
			"//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the",
			"//  GNU General Public License for more details.",
			"// ",
			"//  You should have received a copy of the GNU General Public License",
			"//  along with this program.  If not, see <http://www.gnu.org/licenses/>.",
			"",
			"#include </Derm/Shaders/Compatibility>",
			"",
			"#include </Derm/Shaders/Light/ILightShading>",
			"",
			"// This shader input interface",
			"BEGIN_INPUT_BLOCK(ShaderVaryings)",
			"	// Processed vertex color",
			"	SHADER_IN vec4 ds_Color;",
			"	// Processed vertex position",
			"	SHADER_IN vec4 ds_Position;",
			"	// Processed vertex normal",
			"	SHADER_IN vec3 ds_Normal;",
			"	// Processed vertex texture coordinates",
			"	SHADER_IN vec2 ds_TexCoord[3];",
			"END_INPUT_BLOCK()",
			"",
			"uniform sampler2D ds_MaterialDiffuseTexture;",
			"",
			"// Fragment color",
			"OUT vec4		ds_FragColor;",
			"",
			"// Fragment shader entry point",
			"void main()",
			"{",
			"#if defined(DS_COLOR_PER_VERTEX) || defined(DS_LIGHTING_PER_VERTEX)",
			"",
			"	// Vertex shader computes fragment color",
			"	ds_FragColor = ds_Color;",
			"",
			"#elif defined(DS_LIGHTING_PER_FRAGMENT)",
			"",
			"	// Material initially defined by uniform colors",
			"	ds_MaterialType fragmentMaterial = ds_FrontMaterial;",
			"",
			"	// Diffuse color from texture",
			"	if (ds_FrontTexMaterial.DiffuseTexCoord >= 0)",
			"		fragmentMaterial.DiffuseColor = TEXTURE_2D(ds_FrontTexMaterial.DiffuseTexture, ds_TexCoord[ds_FrontTexMaterial.DiffuseTexCoord]);",
			"",
			"	// Fragment color",
			"	ds_FragColor = ComputeLightShading(fragmentMaterial, ds_Position, normalize(ds_Normal));",
			"",
			"#else",
			"",
			"	// Default to white",
			"	ds_FragColor = vec4(1.0);",
			"",
			"#endif",
			"}",
		};

		#endregion
	}

	/// <summary>
	/// Shader include extracted from ShaderInputs.
	/// </summary>
	public class ShaderInputs : ShaderInclude
	{
		#region Constructors

		/// <summary>
		/// Construct a ShaderInputs.
		/// </summary>
		public ShaderInputs() : base("/Derm/Shaders/Standard/ShaderInputs", sShaderInclude) { }

		#endregion

		#region ShaderInclude Source Code

		/// <summary>
		/// The shader include source code.
		/// </summary>
		private static readonly string[] sShaderInclude = new string[] {
			"#ifndef _DERM_SHADER_STANDARD_VERTEX_INPUTS_\n",
			"#define _DERM_SHADER_STANDARD_VERTEX_INPUTS_\n",
			"#include </Derm/Shaders/Compatibility>\n",
			"// Vertex position\n",
			"ATTRIBUTE vec4 ds_VertexPosition;\n",
			"// Vertex color\n",
			"ATTRIBUTE vec4 ds_VertexColor;\n",
			"// Vertex normal\n",
			"ATTRIBUTE vec3 ds_VertexNormal;\n",
			"#if __VERSION__ >= 130\n",
			"// Vertex texture coordinates\n",
			"ATTRIBUTE vec2 ds_VertexTexCoord[3];\n",
			"#define DS_TEXTURE_ATTRIBUTE(i) ds_VertexTexCoord[i]\n",
			"#else\n",
			"// Vertex texture coordinates\n",
			"ATTRIBUTE vec2 ds_VertexTexCoord0;\n",
			"// Vertex texture coordinates\n",
			"ATTRIBUTE vec2 ds_VertexTexCoord1;\n",
			"// Vertex texture coordinates\n",
			"ATTRIBUTE vec2 ds_VertexTexCoord2;\n",
			"#define DS_TEXTURE_ATTRIBUTE(i) ds_VertexTexCoord ## i\n",
			"#endif\n",
			"#endif\n",
		};

		#endregion
	}

}

